/**
 * Cron表达式生成器
 * 用于生成和解析Cron表达式
 */
export class CronGenerator {
  constructor() {
    this.second = '*';
    this.minute = '*';
    this.hour = '*';
    this.day = '*';
    this.month = '*';
    this.week = '?';
    this.year = '*';
  }

  /**
   * 设置秒字段
   * @param {string} type 类型：every, cycle, specific
   * @param {object} config 配置对象
   */
  setSecond(type, config) {
    switch (type) {
      case 'every':
        this.second = '*';
        break;
      case 'cycle':
        this.second = `${config.start}-${config.end}`;
        break;
      case 'specific':
        this.second = config.specificList.sort((a, b) => a - b).join(',') || '*';
        break;
      default:
        this.second = '*';
    }
  }

  /**
   * 设置分钟字段
   * @param {string} type 类型：every, cycle, specific
   * @param {object} config 配置对象
   */
  setMinute(type, config) {
    switch (type) {
      case 'every':
        this.minute = '*';
        break;
      case 'cycle':
        this.minute = `${config.start}-${config.end}`;
        break;
      case 'specific':
        this.minute = config.specificList.sort((a, b) => a - b).join(',') || '*';
        break;
      default:
        this.minute = '*';
    }
  }

  /**
   * 设置小时字段
   * @param {string} type 类型：every, cycle, specific
   * @param {object} config 配置对象
   */
  setHour(type, config) {
    switch (type) {
      case 'every':
        this.hour = '*';
        break;
      case 'cycle':
        this.hour = `${config.start}-${config.end}`;
        break;
      case 'specific':
        this.hour = config.specificList.sort((a, b) => a - b).join(',') || '*';
        break;
      default:
        this.hour = '*';
    }
  }

  /**
   * 设置日期字段
   * @param {string} type 类型：every, cycle, specific, workday, lastday
   * @param {object} config 配置对象
   */
  setDay(type, config) {
    switch (type) {
      case 'every':
        this.day = '*';
        this.week = '?';
        break;
      case 'cycle':
        this.day = `${config.start}-${config.end}`;
        this.week = '?';
        break;
      case 'specific':
        this.day = config.specificList.sort((a, b) => a - b).join(',') || '*';
        this.week = '?';
        break;
      case 'workday':
        this.day = `${config.workday}W`;
        this.week = '?';
        break;
      case 'lastday':
        this.day = 'L';
        this.week = '?';
        break;
      default:
        this.day = '*';
        this.week = '?';
    }
  }

  /**
   * 设置月份字段
   * @param {string} type 类型：every, cycle, specific
   * @param {object} config 配置对象
   */
  setMonth(type, config) {
    switch (type) {
      case 'every':
        this.month = '*';
        break;
      case 'cycle':
        this.month = `${config.start}-${config.end}`;
        break;
      case 'specific':
        this.month = config.specificList.sort((a, b) => a - b).join(',') || '*';
        break;
      default:
        this.month = '*';
    }
  }

  /**
   * 设置星期字段
   * @param {string} type 类型：every, cycle, specific, lastweek, nthweek
   * @param {object} config 配置对象
   */
  setWeek(type, config) {
    switch (type) {
      case 'every':
        this.week = '?';
        break;
      case 'cycle':
        this.week = `${config.start}-${config.end}`;
        this.day = '?';
        break;
      case 'specific':
        this.week = config.specificList.sort((a, b) => a - b).join(',') || '?';
        this.day = '?';
        break;
      case 'lastweek':
        this.week = `${config.lastweek}L`;
        this.day = '?';
        break;
      case 'nthweek':
        this.week = `${config.nthweekday}#${config.nth}`;
        this.day = '?';
        break;
      default:
        this.week = '?';
    }
  }

  /**
   * 设置年份字段
   * @param {string} type 类型：every, cycle, specific
   * @param {object} config 配置对象
   */
  setYear(type, config) {
    switch (type) {
      case 'every':
        this.year = '*';
        break;
      case 'cycle':
        this.year = `${config.start}-${config.end}`;
        break;
      case 'specific':
        this.year = config.specificList.sort((a, b) => a - b).join(',') || '*';
        break;
      default:
        this.year = '*';
    }
  }

  /**
   * 生成Cron表达式
   * @returns {string} Cron表达式
   */
  generate() {
    return `${this.second} ${this.minute} ${this.hour} ${this.day} ${this.month} ${this.week} ${this.year}`;
  }

  /**
   * 获取下一次执行时间
   * @param {string} cronExpression Cron表达式
   * @param {number} count 获取次数
   * @returns {Array<string>} 下一次执行时间数组
   */
  static getNextExecutionTimes(cronExpression, count = 5) {
    // 这里是一个简单的实现，实际项目中可能需要使用专门的库来解析Cron表达式
    try {
      const times = [];
      let date = new Date();
      
      for (let i = 0; i < count; i++) {
        date = this.getNextExecutionTime(cronExpression, date);
        times.push(this.formatDate(date));
        // 向前推进1秒，避免获取到相同时间
        date.setSeconds(date.getSeconds() + 1);
      }
      
      return times;
    } catch (error) {
      console.error('计算执行时间出错:', error);
      return ['无法计算执行时间，请检查表达式'];
    }
  }

  /**
   * 获取下一次执行时间
   * @param {string} cronExpression Cron表达式
   * @param {Date} baseDate 基准时间
   * @returns {Date} 下一次执行时间
   */
  static getNextExecutionTime(cronExpression, baseDate) {
    // 这里是一个简化的实现，实际项目中应该使用专门的库
    // 这个简化版本只是为了演示，不能处理复杂的Cron表达式
    const parts = cronExpression.split(' ');
    if (parts.length < 6) {
      throw new Error('无效的Cron表达式');
    }

    // 简单模拟：每次增加1分钟
    const nextDate = new Date(baseDate);
    nextDate.setMinutes(nextDate.getMinutes() + 1);
    return nextDate;
  }

  /**
   * 格式化日期
   * @param {Date} date 日期对象
   * @returns {string} 格式化后的日期字符串
   */
  static formatDate(date) {
    const pad = (num) => String(num).padStart(2, '0');
    
    const year = date.getFullYear();
    const month = pad(date.getMonth() + 1);
    const day = pad(date.getDate());
    const hour = pad(date.getHours());
    const minute = pad(date.getMinutes());
    const second = pad(date.getSeconds());
    
    return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
  }

  /**
   * 解析Cron表达式
   * @param {string} cronExpression Cron表达式
   * @returns {object} 解析后的配置对象
   */
  static parse(cronExpression) {
    const parts = cronExpression.split(' ');
    if (parts.length < 6) {
      throw new Error('无效的Cron表达式');
    }
    
    // 解析各个字段
    const secondConfig = this.parseField(parts[0], 0, 59);
    const minuteConfig = this.parseField(parts[1], 0, 59);
    const hourConfig = this.parseField(parts[2], 0, 23);
    const dayConfig = this.parseDayField(parts[3]);
    const monthConfig = this.parseField(parts[4], 1, 12);
    const weekConfig = this.parseWeekField(parts[5]);
    const yearConfig = parts.length > 6 ? this.parseField(parts[6], 2000, 2100) : { type: 'every', specificList: [] };
    
    return {
      second: secondConfig,
      minute: minuteConfig,
      hour: hourConfig,
      day: dayConfig,
      month: monthConfig,
      week: weekConfig,
      year: yearConfig
    };
  }

  /**
   * 解析普通字段
   * @param {string} field 字段值
   * @param {number} min 最小值
   * @param {number} max 最大值
   * @returns {object} 解析后的配置对象
   */
  static parseField(field, min, max) {
    const config = {
      type: 'every',
      start: min,
      end: max,
      specificList: []
    };
    
    if (field === '*') {
      config.type = 'every';
    } else if (field.includes('-')) {
      config.type = 'cycle';
      const [start, end] = field.split('-').map(Number);
      config.start = start;
      config.end = end;
    } else if (field.includes(',')) {
      config.type = 'specific';
      config.specificList = field.split(',').map(Number);
    } else if (!isNaN(Number(field))) {
      config.type = 'specific';
      config.specificList = [Number(field)];
    }
    
    return config;
  }

  /**
   * 解析日期字段
   * @param {string} field 字段值
   * @returns {object} 解析后的配置对象
   */
  static parseDayField(field) {
    const config = {
      type: 'every',
      start: 1,
      end: 31,
      specificList: [],
      workday: 1
    };
    
    if (field === '*') {
      config.type = 'every';
    } else if (field === 'L') {
      config.type = 'lastday';
    } else if (field.includes('W')) {
      config.type = 'workday';
      config.workday = parseInt(field.replace('W', ''), 10);
    } else if (field.includes('-')) {
      config.type = 'cycle';
      const [start, end] = field.split('-').map(Number);
      config.start = start;
      config.end = end;
    } else if (field.includes(',')) {
      config.type = 'specific';
      config.specificList = field.split(',').map(Number);
    } else if (!isNaN(Number(field))) {
      config.type = 'specific';
      config.specificList = [Number(field)];
    }
    
    return config;
  }

  /**
   * 解析星期字段
   * @param {string} field 字段值
   * @returns {object} 解析后的配置对象
   */
  static parseWeekField(field) {
    const config = {
      type: 'every',
      start: 1,
      end: 7,
      specificList: [],
      lastweek: 1,
      nth: 1,
      nthweekday: 1
    };
    
    if (field === '?' || field === '*') {
      config.type = 'every';
    } else if (field.includes('#')) {
      config.type = 'nthweek';
      const [weekday, nth] = field.split('#').map(Number);
      config.nthweekday = weekday;
      config.nth = nth;
    } else if (field.includes('L') && field !== 'L') {
      config.type = 'lastweek';
      config.lastweek = parseInt(field.replace('L', ''), 10);
    } else if (field.includes('-')) {
      config.type = 'cycle';
      const [start, end] = field.split('-').map(Number);
      config.start = start;
      config.end = end;
    } else if (field.includes(',')) {
      config.type = 'specific';
      config.specificList = field.split(',').map(Number);
    } else if (!isNaN(Number(field))) {
      config.type = 'specific';
      config.specificList = [Number(field)];
    }
    
    return config;
  }
}
